In this project I would like to cover the analysis and visulaisation of DOU IT salaries reports.
Public stats: http://jobs.dou.ua/salaries/ , https://github.com/devua/csv/tree/master/salaries.
import pandas as pd
import altair as alt
import geopandas as gpd
import os
alt.data_transformers.disable_max_rows()
pd.options.mode.chained_assignment = None
First parts will cover the stats gathered during the latest period : june 2021 including 13175 answers.
#Reading data set from salaries surveys.
df = pd.read_csv("../data/salaries/2021_june_raw.csv")
df.head()
| Позначка часу | Чи працюєте ви зараз? | Де ви мешкаєте? | Ваша стать | Ваш вік | Яка у вас освіта? | Загальний стаж роботи в ІТ | Знання англійської мови | Оберіть вашу посаду | Middle | ... | В якій сфері працюєте ви / ваш поточний проєкт? | Тип компанії | Кількість спеціалістів у вашій компанії (в Україні) | Загальний стаж роботи за нинішньою спеціалізацією | Стаж на поточному місці роботи | Зарплата у $$$ за місяць, лише ставка після сплати податків | Наскільки змінилась ваша зарплата за останні 12 місяців? | Чи отримуєте ви грошові бонуси до зарплати? | Вкажіть суму цього бонуса у після податків | Вкажіть ваш основний заклад вищої освіти (якщо вчилися в кількох – той, де провели найбільше часу) | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 06/02/2021 10:07 | Так, працюю full-time | Київ | Чоловік | 36 | Дві вищих | 10 і більше років | Advanced | Software Engineer (Junior, Middle, Senior, Tea... | Senior | ... | Media, Travel | Продуктова | до 10 спеціалістів | 7 років | 7 років | 4000 | 0 | Ні, не отримую | 0.0 | ХАІ |
| 1 | 06/02/2021 10:08 | Так, працюю full-time | Київ | Чоловік | 22 | Ще студент | 2 роки | Upper-Intermediate | Software Engineer (Junior, Middle, Senior, Tea... | Middle | ... | Fintech | Аутстафінгова | понад 1000 | 2 роки | 3 місяці | 3300 | 800 | Ні, не отримую | 0.0 | НАУ |
| 2 | 06/02/2021 10:08 | Так, працюю full-time | Львів | Чоловік | 29 | Вища | 8 років | Upper-Intermediate | DevOps, SysAdmin | NaN | ... | E-commerce | Аутсорсингова | понад 1000 | 8 років | 8 років | 4800 | 200 | Ні, не отримую | 0.0 | Львівська політехніка |
| 3 | 06/02/2021 10:09 | Так, працюю full-time | Київ | Чоловік | 37 | Вища | 10 і більше років | Intermediate | Support | NaN | ... | Telecom, Інша | Аутстафінгова | понад 1000 | 10 і більше років | 4 роки | 1500 | 0 | Ні, не отримую | 0.0 | НТУУ «КПІ» |
| 4 | 06/02/2021 10:09 | Так, працюю full-time | Вінниця | Чоловік | 29 | Дві вищих | 3 роки | Advanced | Sales Manager | NaN | ... | Інша | Аутсорсингова | до 50 | 3 роки | 1,5 року | 600 | 0 | Отримую бонус щомісяця | 1500.0 | КНУ ім. Шевченка |
5 rows × 43 columns
df.columns
Index(['Позначка часу', 'Чи працюєте ви зараз?', 'Де ви мешкаєте?',
'Ваша стать', 'Ваш вік', 'Яка у вас освіта?',
'Загальний стаж роботи в ІТ', 'Знання англійської мови',
'Оберіть вашу посаду', 'Middle', 'Вкажіть вашу основну спеціалізацію',
'Основна мова програмування', 'Інші мови програмування',
'Фреймворки, бібліотеки та платформи',
'Платформи, для яких розробляєте на поточному місці роботи?',
'Ваш тайтл', 'Вкажіть вашу спеціалізацію',
'Яку мову програмування використовуєте в роботі?',
'Оберіть вашу посаду_1', 'Ваш тайтл_2', 'Ваша посада', 'Ваш тайтл_3',
'Оберіть вашу посаду_4', 'Ваш тайтл_5', 'Ваша посада_6', 'Ваш тайтл_7',
'Ваша посада_8', 'Ваш тайтл_9', 'Ваша посада_10', 'Ваш тайтл_11',
'Ваша посада_12', 'Ваш тайтл_13', 'Ваша посада_14',
'В якій сфері працюєте ви / ваш поточний проєкт?', 'Тип компанії',
'Кількість спеціалістів у вашій компанії (в Україні)',
'Загальний стаж роботи за нинішньою спеціалізацією',
'Стаж на поточному місці роботи',
'Зарплата у $$$ за місяць, лише ставка після сплати податків',
'Наскільки змінилась ваша зарплата за останні 12 місяців?',
'Чи отримуєте ви грошові бонуси до зарплати?',
'Вкажіть суму цього бонуса у після податків',
'Вкажіть ваш основний заклад вищої освіти (якщо вчилися в кількох – той, де провели найбільше часу)'],
dtype='object')
#Extracting data we are intrersted in
df = df[['Де ви мешкаєте?','Ваш вік','Загальний стаж роботи в ІТ', 'Знання англійської мови',
'Middle', 'Ваш тайтл','Основна мова програмування', 'Тип компанії','Оберіть вашу посаду',
'Зарплата у $$$ за місяць, лише ставка після сплати податків']]
#Renaming columns for convenience
df.rename(columns={'Де ви мешкаєте?':'city'}, inplace=True)
df.rename(columns={'Ваш вік':'age'}, inplace=True)
df.rename(columns={'Загальний стаж роботи в ІТ':'total_it_experience'}, inplace=True)
df.rename(columns={'Знання англійської мови':'eng_level'}, inplace=True)
df.rename(columns={'Middle':'seniority'}, inplace=True)
df.rename(columns={'Основна мова програмування':'pr_language'}, inplace=True)
df.rename(columns={'Тип компанії':'company_type'}, inplace=True)
df.rename(columns={'Зарплата у $$$ за місяць, лише ставка після сплати податків':'salary'}, inplace=True)
df.rename(columns={'Ваш тайтл':'title'}, inplace=True)
df.rename(columns={'Оберіть вашу посаду':'position'}, inplace=True)
#Convertning experience to number of years
def convertExperienceToFloat(expirience):
if 'роки'in expirience or 'років' in expirience:
return float(expirience.split()[0])
if 'Менше як'in expirience:
return (float(expirience.split()[2])-1)/12
elif ' місяці'in expirience:
return float(expirience.split()[0])/12
df['total_it_experience'] = df['total_it_experience'].apply(convertExperienceToFloat)
#Ignoring salaries greater then 15000 because of possible missunderstanding of currency input"
df = df[df['salary'] < 15000]
df.head()
| city | age | total_it_experience | eng_level | seniority | title | pr_language | company_type | position | salary | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Київ | 36 | 10.0 | Advanced | Senior | NaN | C# / .NET | Продуктова | Software Engineer (Junior, Middle, Senior, Tea... | 4000 |
| 1 | Київ | 22 | 2.0 | Upper-Intermediate | Middle | NaN | C# / .NET | Аутстафінгова | Software Engineer (Junior, Middle, Senior, Tea... | 3300 |
| 2 | Львів | 29 | 8.0 | Upper-Intermediate | NaN | NaN | NaN | Аутсорсингова | DevOps, SysAdmin | 4800 |
| 3 | Київ | 37 | 10.0 | Intermediate | NaN | NaN | NaN | Аутстафінгова | Support | 1500 |
| 4 | Вінниця | 29 | 3.0 | Advanced | NaN | NaN | NaN | Аутсорсингова | Sales Manager | 600 |
df_p1_q1 = df[['city', 'total_it_experience', 'pr_language', 'salary', 'company_type']]
df_p1_q1.head()
| city | total_it_experience | pr_language | salary | company_type | |
|---|---|---|---|---|---|
| 0 | Київ | 10.0 | C# / .NET | 4000 | Продуктова |
| 1 | Київ | 2.0 | C# / .NET | 3300 | Аутстафінгова |
| 2 | Львів | 8.0 | NaN | 4800 | Аутсорсингова |
| 3 | Київ | 10.0 | NaN | 1500 | Аутстафінгова |
| 4 | Вінниця | 3.0 | NaN | 600 | Аутсорсингова |
Let's take into consideration only most popular programming languages and most popular cities of Ukraine among IT specialists.
def filterLargeCities(city):
if city in ['Київ','Львів','Харків', 'Дніпро', 'Івано-Франківськ', 'Вінниця']:
return city
else:
return 'Інше'
df_p1_q1['city'] = df_p1_q1['city'].apply(filterLargeCities)
df_p1_q1 = df_p1_q1[df_p1_q1['pr_language'].isin(['C++', 'Java', 'Python', 'Ruby', 'Swift', 'PHP', 'C# / .NET', 'JavaScript'])]
df_p1_q1.head()
| city | total_it_experience | pr_language | salary | company_type | |
|---|---|---|---|---|---|
| 0 | Київ | 10.0 | C# / .NET | 4000 | Продуктова |
| 1 | Київ | 2.0 | C# / .NET | 3300 | Аутстафінгова |
| 5 | Вінниця | 2.0 | Java | 1900 | Продуктова |
| 7 | Львів | 4.0 | C# / .NET | 3500 | Продуктова |
| 9 | Київ | 5.0 | Java | 4500 | Стартап |
alt.Chart(df_p1_q1).mark_line().encode(
x= alt.X('total_it_experience', title='Years of experience', axis=alt.Axis(tickMinStep=1)),
y= alt.Y('mean(salary):Q', title='Average salary'),
color=alt.Color('pr_language',title='Primary language')
).properties(width=700, title='Salary curve by total IT experience for different programming languages').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
color='Black'
)
alt.Chart(df_p1_q1).mark_line().encode(
x= alt.X('total_it_experience', title='Years of experience', axis=alt.Axis(tickMinStep=1)),
y= alt.Y('mean(salary):Q', title='Average salary'),
color=alt.Color('city', title='City')
).properties(width=700, title='Salary curve by total IT experience for Ukrainian cities').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
color='Black'
)
alt.Chart(df_p1_q1).mark_line().encode(
x= alt.X('total_it_experience', title='Years of experience', axis=alt.Axis(tickMinStep=1)),
y= alt.Y('mean(salary):Q', title='Average salary'),
color=alt.Color('company_type', title='Company type')
).properties(width=700, title='Salary curve by total IT experience for different company types').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
color='Black'
)
Provided visualisations were created to see if there is some correlation between the salary and specialists' skills. What is more, to see the picture more specificly, it was intresting to exemine this correlations in the context of some external parameters like location and company type. Linear charts showed the dependencies and differencies quite clear.
df_p2 = df[['city','seniority', 'salary', 'position', 'title']]
df_p2['city'] = df_p2['city'].apply(filterLargeCities)
df_p2.head()
| city | seniority | salary | position | title | |
|---|---|---|---|---|---|
| 0 | Київ | Senior | 4000 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 1 | Київ | Middle | 3300 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 2 | Львів | NaN | 4800 | DevOps, SysAdmin | NaN |
| 3 | Київ | NaN | 1500 | Support | NaN |
| 4 | Вінниця | NaN | 600 | Sales Manager | NaN |
df_p2_q1 = df_p2[df_p2['position'] == 'Software Engineer (Junior, Middle, Senior, Team / Tech Lead, Architect)']
df_p2_q1.head()
| city | seniority | salary | position | title | |
|---|---|---|---|---|---|
| 0 | Київ | Senior | 4000 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 1 | Київ | Middle | 3300 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 5 | Вінниця | Middle | 1900 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 7 | Львів | Middle | 3500 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
| 9 | Київ | Senior | 4500 | Software Engineer (Junior, Middle, Senior, Tea... | NaN |
alt.Chart(df_p2_q1).mark_bar().encode(
x=alt.X('city:N', title=''),
y=alt.Y('salary:Q', title=''),
color=alt.Color('city:N', title='City'),
column=alt.Column('seniority:N',
sort=['Intern / Trainee', 'Junior', 'Middle', 'Senior', 'Team Lead', 'Tech Lead', 'Architect'],
title='')
).properties(width=100, title='Salary rates for Software Engineers of different seniority levels ').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
dy=-20,
dx=-50,
color='Black'
)
df_p2_q2 = df_p2[df_p2['position'] == 'QA Engineer (Junior, Middle, Senior, Team / Tech Lead, Manager)']
df_p2_q2.head()
| city | seniority | salary | position | title | |
|---|---|---|---|---|---|
| 8 | Київ | NaN | 2500 | QA Engineer (Junior, Middle, Senior, Team / Te... | Middle |
| 10 | Київ | NaN | 4000 | QA Engineer (Junior, Middle, Senior, Team / Te... | Senior |
| 21 | Дніпро | NaN | 1800 | QA Engineer (Junior, Middle, Senior, Team / Te... | Middle |
| 22 | Дніпро | NaN | 2500 | QA Engineer (Junior, Middle, Senior, Team / Te... | Senior |
| 29 | Київ | NaN | 1900 | QA Engineer (Junior, Middle, Senior, Team / Te... | Middle |
alt.Chart(df_p2_q2).mark_bar().encode(
x=alt.X('city:N', title=''),
y=alt.Y('salary:Q', title=''),
color=alt.Color('city:N', title='City'),
column=alt.Column('title:N', sort=['Intern / Trainee', 'Junior', 'Middle', 'Senior', 'Team Lead', 'Tech Lead', 'Manager'],
title='')
).properties(width=100, title='Salary rates for QA Engineers of different seniority levels ').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
dy=-20,
dx=-50,
color='Black'
)
In this part my goal was to see what is a typical average salaty rate for IT specialists of different levels. But as rates differ for different Ulrainian cities, the data was separated by location parameter. Grouped bar charts perfeclty matched for the solution and helped to visualize data divided by both : seniority level and city.
For this part we will use all final reports from 2013-2020 years.
filesnames = os.listdir('../data/salaries')
filesnames = [f for f in filesnames if (f.lower().endswith("final.csv"))]
dfs = list()
for filename in filesnames:
df_file = pd.read_csv("../data/salaries/" + filename)
dfs.append(df_file)
df_p3 = pd.concat(dfs)
#Extracting data we are intrersted in
df_p3_q1 = df_p3[['Дата.заполнения','Должность','Язык.программирования','Общий.опыт.работы', 'Город', 'Зарплата.в.месяц', 'cls']]
#Renaming columns for convenience
df_p3_q1.rename(columns={'Дата.заполнения':'date'}, inplace=True)
df_p3_q1.rename(columns={'Должность':'position'}, inplace=True)
df_p3_q1.rename(columns={'Язык.программирования':'pr_lanuage'}, inplace=True)
df_p3_q1.rename(columns={'Общий.опыт.работы':'total_it_experience'}, inplace=True)
df_p3_q1.rename(columns={'Зарплата.в.месяц':'salary'}, inplace=True)
df_p3_q1.rename(columns={'Город':'city'}, inplace=True)
df_p3_q1.head()
| date | position | pr_lanuage | total_it_experience | city | salary | cls | |
|---|---|---|---|---|---|---|---|
| 1 | 20/12/2013 12:00:56 | Software Engineer | Java | 1.5 | Львов | 1300.0 | DEV |
| 2 | 20/12/2013 12:01:53 | HR | NaN | 1.5 | Киев | 700.0 | NaN |
| 3 | 20/12/2013 12:05:31 | Junior Software Engineer | Java | 0.25 | Днепр. | 750.0 | DEV |
| 4 | 20/12/2013 12:05:53 | Senior Software Engineer | C#/.NET | 6.5 | Киев | 2700.0 | DEV |
| 5 | 20/12/2013 12:06:07 | Project manager | NaN | 3 | Львов | 1800.0 | PM |
#Extracting the data for developers with valid salary input
df_p3_q1 = df_p3_q1[df_p3_q1['cls'] == 'DEV']
df_p3_q1 = df_p3_q1[df_p3_q1['salary'] < 10000]
df_p3_q1.head()
| date | position | pr_lanuage | total_it_experience | city | salary | cls | |
|---|---|---|---|---|---|---|---|
| 1 | 20/12/2013 12:00:56 | Software Engineer | Java | 1.5 | Львов | 1300.0 | DEV |
| 3 | 20/12/2013 12:05:31 | Junior Software Engineer | Java | 0.25 | Днепр. | 750.0 | DEV |
| 4 | 20/12/2013 12:05:53 | Senior Software Engineer | C#/.NET | 6.5 | Киев | 2700.0 | DEV |
| 7 | 20/12/2013 12:08:43 | Software Engineer | Java | 3 | Львов | 3000.0 | DEV |
| 8 | 20/12/2013 12:09:47 | Software Engineer | Java | 5 | Киев | 4600.0 | DEV |
from IPython.display import display, HTML
display(HTML("""
<style>
form.vega-bindings {
position: absolute;
left: 0px;
top: 0px;
}
</style>
"""))
input_dropdown = alt.binding_select(options = df_p3_q1.pr_lanuage.unique(), name='Select language ')
selection = alt.selection_single(fields = ['pr_lanuage'], bind = input_dropdown)
alt.Chart(df_p3_q1).add_selection(selection).mark_line(point = True).encode(
x = alt.X("date:O", timeUnit="yearmonth", title=None),
y='mean(salary):Q',
color='position:N',
tooltip=[alt.Tooltip('count(salary)', title='Answers count'),
alt.Tooltip('mean(salary)', format="d"),
alt.Tooltip('yearmonth(date)', title='Month, year')]
).transform_filter(
selection
).properties(width=800, height=400,
title='Dynamics of IT salaries in Ukraine by programming languages').configure_title(
fontSize=15,
font='Arial',
anchor='middle',
dy=-10,
color='Black'
)